package com.open.spring.utils;

import java.util.HashMap;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;


/**
 * Bean管理器。
 * 设计的初衷是用来配合spring使用。
 * 在Spring的启动xml中创建一个BeanUtil的实例，用于感应Spring的ApplicationContext。
 * 当AppliationContext存在时，使用BeanUtil的getBean就可以获得指定名称的指定类别之对象。
 * @author Lanny Lee
 *
 */
public class BeanUtil implements ApplicationContextAware {
	
	private static ApplicationContext springContext = null;
	private static HashMap<String, Object> localBeanPool = null;
	@Override
	public void setApplicationContext(ApplicationContext ctx) throws BeansException {
		springContext = ctx;
	}
	
	private static void ensureLocalBeanPool() {
		if (localBeanPool == null) localBeanPool = new HashMap<String, Object>();
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name, Class<T> t) throws BeansException {
		T o = null;
		if (springContext != null) {
			//在spring环境下，采用spring的ApplicationContext获得对象；
			o = springContext.getBean(name, t);
		} else {
			//若不在spring环境中，则创建自有的bean池
			//自有bean池所得的对象，并不能保证线程安全，因此仅适用于测试用途
			ensureLocalBeanPool();
			if (localBeanPool.containsKey(name)) {
				Object obj = localBeanPool.get(name);
				//具有此名称的Bean并且类型==t，则返回所得的对象。
				if (obj != null && obj.getClass().equals(t)) {
					o = (T) obj;
				}
			} else {
				try {
					//创建新的t实例，写入bean池以及返回此实例
					o = t.newInstance();
					localBeanPool.put(name, o);
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					o = null;
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					o = null;
					e.printStackTrace();
				}
			}
		}
		return o;
	}

	/**
	 * 获取Class<T>的单一实例
	 * @param t
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(Class<T> t) throws BeansException {
		T o = null;
		if (springContext != null) {
			//在spring环境下，采用spring的ApplicationContext获得对象；
			o = springContext.getBean(t);
		} else {
			//若不在spring环境中，则创建自有的bean池
			//自有bean池所得的对象，并不能保证线程安全，因此仅适用于测试用途
			ensureLocalBeanPool();
			String key = "__SINGLETONE_" + t.getName();
			if (localBeanPool.containsKey(key)) {
				Object obj = localBeanPool.get(key);
				//具有此名称的Bean并且类型==t，则返回所得的对象。
				if (obj != null && obj.getClass().equals(t)) {
					o = (T) obj;
				}
			} else {
				try {
					//创建新的t实例，写入bean池以及返回此实例
					o = t.newInstance();
					localBeanPool.put(key, o);
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					o = null;
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					o = null;
					e.printStackTrace();
				}
			}
		}
		return o;
	}
	
	public static Object getBean(String name) {
		Object o = null;
		if (springContext != null) {
			//在spring环境下，采用spring的ApplicationContext获得对象；
			o = springContext.getBean(name);
		} else {
			//若不在spring环境中，则创建自有的bean池
			//自有bean池所得的对象，并不能保证线程安全，因此仅适用于测试用途
			ensureLocalBeanPool();
			String key = name;
			if (localBeanPool.containsKey(key)) {
				Object obj = localBeanPool.get(key);
				//具有此名称的Bean并且类型==t，则返回所得的对象。
				if (obj != null) {
					o = obj;
				}
			}
		}
		return o;
	}
	
	
}
